package org.mtmi.ui.controls;

import java.util.ArrayList;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.mtmi.tuio.listeners.SingleTapListener;
import org.mtmi.tuio.listeners.TUIOTapEvent;
import org.mtmi.ui.GraphicUtil;
import org.mtmi.ui.M;
import org.mtmi.ui.controls.listeners.MenuSelectionListener;
import org.mtmi.ui.layouts.LayoutData;
import org.mtmi.ui.scenes.AnimationManager;
import org.mtmi.ui.scenes.COLOR;
import org.mtmi.ui.scenes.FontManager;
import org.mtmi.ui.scenes.IAnimated;
import org.mtmi.ui.scenes.Scene;

public class FlowerMenu extends Control implements SingleTapListener, ITouchableControl, IAnimated
{
	private class Bubble extends Control implements SingleTapListener, ITouchableControl
	{
		private String text;
		private int id;
		private int cx,cy, r;

		Bubble( Scene s, String t, int _id, int x, int y, int _flags ) {
			super( s, _flags );
			text = t;
			id = _id;
			cx =x;
			cy=y;
		}
		
		@Override
		public Point computeSize(LayoutData l) {
			// TODO merger avec computeradius ?
			int r = computeRadius( l.gc );
			return new Point( r+r, r+r );
		}

		public int getR() { return r; }
		public void setR( int _r ) { r=_r; }
		public void setCenter( int _x, int _y ) { cx=_x; cy=_y; }

		int computeRadius( GC gc ) {
			Point s = gc.textExtent( text );
			int dx = s.x/2, dy = s.y/2;
			r = 5+ (int)Math.sqrt( dx*dx+dy*dy );
			return r;
		}

		public void paint( GC gc ) {
			gc.setAntialias( SWT.ON );
			Point s = gc.textExtent( text );
			int dx = s.x/2, dy = s.y/2;
			//int r = 5+ (int)Math.sqrt( dx*dx+dy*dy );

			gc.setBackground( FlowerMenu.this.getBackground() );
			gc.fillOval( cx-r, cy-r, r+r, r+r );
			gc.setForeground( FlowerMenu.this.getForeground() );
			gc.setLineWidth( borderWidth );
			gc.drawOval( cx-r, cy-r, r+r, r+r );
			gc.setForeground( FlowerMenu.this.getTextColor() );
			gc.drawText( text, cx-dx, cy-dy, true );
		}

		@Override
		public void tapDown(TUIOTapEvent event) {
		}

		@Override
		public void tapUp(TUIOTapEvent event) {
			close();
			fireMenuItem( id );
		}

		@Override
		public boolean containsTouch(TouchControlEvent e) {
			return GraphicUtil.circleContains( cx, cy, r, e.x, e.y );
		}
	}

	private ArrayList<Bubble> bubbles;
	private int cx, cy;
	private boolean layouted;
	private int animStep;
	private ArrayList<MenuSelectionListener> lis_menu;
	private Color c_text;
	
	public FlowerMenu( Scene scene, int _flags ) {
		super( scene, _flags );
		bubbles = new ArrayList<Bubble>();
		//default colors:
		setForeground( COLOR.grey100 );
		setBackground( COLOR.grey0 );
		c_text = COLOR.grey60;
	}
	
	public void setTextColor( Color c ) { c_text=c; }
	public Color getTextColor() { return c_text ;}
	
	public void clear() {
		//note: close() has disposed all bubbles
		bubbles.clear();
	}
	
	public void addItem( String t, int id ) {
		Bubble b = new Bubble( getScene(), t, id, 0,0, (flags & M.SCENE_EDITOR_CONTROL) );
		bubbles.add( b );
		layouted=false;
	}
	
	@Override
	public Point computeSize(LayoutData l) {
		// TODO a faire, mais c'est fait dans open() ....
		return new Point( 0, 0);
	}
	
	/** open menu centered on control bounds */
	public void open( Control c ) {
		Point p = c.getLocation();
		Point s = c.getSize();
		open( p.x+s.x/2, p.y+s.y/2 );
	}
	/** open menu centered on control bounds */
	public void open( ITouchableControl c ) {
		Point l = c.getLocation();
		Point s = c.getSize();
		open( l.x+s.x/2, l.y+s.y/2 );
	}

	public void open( int _cx, int _cy ) {
		cx = _cx;
		cy = _cy;

		GC gc = new GC( getScene() );
		gc.setFont( FontManager.getInstance().getNormalFont() );
		int r1= 0;

		for( Bubble b : bubbles ) {
			r1 = Math.max( r1, b.computeRadius( gc ) );
		}
		r1 = Math.max( 30, r1 ); //min: finger must select bubble

		//placer les bubble en quinconce (! pb si nbre impair)
		boolean xach = false ;

		double da_max = 2*Math.PI;
		int R = 50;
		double da = 0, a=0;
		boolean adjusted=false;
		do {
			da = 2*Math.asin( (r1+2)/(float)R ) ; //+ Math.PI/32;
			if( xach ) {
				int n = bubbles.size()/2 +( bubbles.size()%2==1 ? 1 : 0) ;
				a = n*da;
			} else {
				a = bubbles.size() * da;
			}
			if( a <= da_max ) break;
			R+=10;
			adjusted=true;
		} while( true );

		if(  adjusted ) {
			int n = bubbles.size();
			if( xach ) n = 2*( bubbles.size()/2 +( bubbles.size()%2==1 ? 1 : 0) );
			da = (da_max) / n;
		}
		
		//adjust menu center location if bubble is out of screen
		Point sz = getScene().getSize();
		if( cx-R-r1 < 0 ) {
			cx = R+r1+5;
		} else if( cx+R+r1 > sz.x ) {
			cx = sz.x-R-r1;
		}
		if( cy-R-r1 < 0 ) {
			cy = R+r1+5;
		} else if( cy+R+r1 > sz.y ) {
			cy = sz.y-R-r1;
		}
		

		//da /=2;

		a = 0;
		int i=0;
		for( Bubble b : bubbles ) {
			b.setR( r1 );
			int rr = xach ? ( (i%2==0) ? R : R+2*r1+5 ) : R;
			int x = cx+(int)Math.round( rr*Math.cos( a ) );
			int y = cy+(int)Math.round( rr*Math.sin( a ) );
			b.setCenter( x, y );
			a+=da;
			i++;
		}
		gc.dispose();
		layouted=true;
		if( AnimationManager.getDefault().add( this ) ) {
			animStep=1; //grow
		}
		getScene().redraw();
	}
	
	public void close() {
		layouted=false;
		for( Bubble b: bubbles ) {
			b.dispose();
		}
		dispose();
		getScene().redraw();
	}

	private static int r=30; //central radius
	
	@Override
	public void paint(GC gc) {
		if( !layouted ) return ;
		gc.setAntialias( SWT.ON );
		gc.setForeground( getForeground() );
		gc.setLineWidth( borderWidth );
		gc.setFont( FontManager.getInstance().getNormalFont() );
		gc.drawOval( cx-r, cy-r, r+r, r+r );
		for( Bubble b : bubbles ) {
			gc.drawLine( cx, cy, b.cx, b.cy );
		}
		gc.setBackground( getBackground() );
		gc.fillOval( cx-r, cy-r, r+r, r+r );
		gc.setForeground( getForeground() );
		gc.setLineWidth( borderWidth );
		gc.drawOval( cx-r, cy-r, r+r, r+r );

		//now: bubble are also controls no need to paint them again
		if( animStep!= 0 ) {
			for( Bubble b : bubbles ) {
				int scx = b.cx, scy=b.cy;
				if( animStep>0 && animStep<=100 ) {
					int dx = b.cx-cx, dy = b.cy-cy;
					float k = animStep/100f;
					b.setCenter( Math.round(cx+dx*k), Math.round(cy+dy*k) ) ;
				}
				b.paint( gc );
				b.setCenter( scx, scy );
			}
		}
	}


	@Override
	public void tapDown(TUIOTapEvent event) {
		if( layouted ) {
			Rectangle ca= getScene().getClientArea();
			int ex = Math.round(event.x*ca.width);
			int ey = Math.round(event.y*ca.height);
			int dx = ex-cx, dy=ey-cy;
			int r2 = dx*dx+dy*dy;
			if( r2<=r*r ) {
				close();
			}
		}
	}


	@Override
	public void tapUp(TUIOTapEvent event) {
	}


	@Override
	public boolean containsTouch(TouchControlEvent e) {
		if( layouted ) {
			return GraphicUtil.circleContains( cx, cy, r, e.x, e.y );
		} else {
			return false;
		}
	}
	
	public void addMenuSelectionListener( MenuSelectionListener lis ) {
		if( lis_menu==null ) {
			lis_menu = new ArrayList<MenuSelectionListener>();
		}
		lis_menu.add( lis );
	}
	
	public void removeMenuSelectionListener( MenuSelectionListener lis ) {
		if( lis_menu!=null ) {
			lis_menu.remove( lis );
		}
	}

	private void fireMenuItem( int id ) {
		if( lis_menu==null ) return ;
		MenuSelectionListener ls[] = lis_menu.toArray( new MenuSelectionListener[0] );
		for( int i=0; i<ls.length; i++ ) {
			ls[i].menuEntrySelected( id );
		}
	}


	@Override
	public boolean animationStep() {
		if( animStep>=100 ) {
			animStep=0; //stop
		}
		else if( animStep<100 ) {
			animStep+=15;
			if( animStep>100 ) animStep=100;
		}
		return animStep!=0;
	}

	@Override
	public boolean isAnimating() {
		return animStep!=0;
	}

}
